%!PS-Adobe-3.0 Resource-ProcSet
%%EndComments

20 dict begin

% (utf-8-string) ushow -
/ushow {
	deutf { 						% c
		ushow.findglyph {				% c /glyph
			ushow.printglyph			% 
		} {						% c
			ushow.substitute
		} ifelse
	} forall						% 
} def

% (utf-8-string) ustringwidth w 0
/ustringwidth {
	0 exch deutf { 
		ushow.findglyph {
			.glyphwidth pop exch pop
		} {
			ushow.substwidth
		} ifelse add
	} forall 0.0
} def

% Decode utf-8
%
% (utf8-string) -> [ codepoint codepoint ... codepoint ]
%
% in case of malformed string, codepoint -1 is inserted where
% the parser failed to interpret data.

/deutf {
	mark exch 0 exch { {		% expect c
		% continuation byte
		dup 2#11000000 and 2#10000000 eq {
			% check whether we're in the middle
			% of sequence
			1 index 0 gt {
				% ok, add this to the last codepoint
				2#00111111 and
				3 2 roll 6 bitshift or
				exch 1 sub
			} {
				% nope, malformed string
				pop -1 0
			} ifelse
			exit
		} if

		% non-continuation byte while we're in the middle
		% of sequence
		1 index 0 ne { pop -1 0 exit } if

		% 0-, 1-, ..., 5-seq. starting bytes
		dup 2#10000000 and 2#00000000 eq { exch exit } if
		dup 2#11100000 and 2#11000000 eq { 2#00011111 and exch pop 1 exit } if
		dup 2#11110000 and 2#11100000 eq { 2#00001111 and exch pop 2 exit } if
		dup 2#11111000 and 2#11110000 eq { 2#00000111 and exch pop 3 exit } if
		dup 2#11111100 and 2#11111000 eq { 2#00000011 and exch pop 4 exit } if
		dup 2#11111110 and 2#11111100 eq { 2#00000001 and exch pop 5 exit } if
		% ignored code -- should not happen, but anyway
		pop exit
	} loop } forall
	% check for incomplete string
	0 ne { -1 } if
	counttomark array astore exch pop
} def

% Find glyph name for codepoint $uni in current font.
%
% uni -> uni /glyphname true
% uni -> uni false
%
% What this actually does is making a list of possible names,
% say, [ /uni0020 /space /spacehackarabic ], and then trying
% each of them against currentfont's CharStrings.

/ushow.findglyph {
	currentfont /CharStrings get false			% uni CS F

	[ 3 index ushow.uniname					% uni CS F [ un
	  ReverseGlyphList 5 index .knownget {			% uni CS F [ un nns
		dup type /arraytype eq { aload pop } if		% uni CS F [ un n n ...
	  } if
	] {							% uni CS F name
		2 index 1 index known {				% uni CS F name
			exch pop true exit
		} {
			pop
		} ifelse
	} forall						% uni CS name? TF

	{ exch pop true } { pop false } ifelse
} def

% Fallback glyph name, for characters not in AGL: /uni(code),
% with (code) = %04X the actual unicode value.
% Sadly this is only a fallback option, since fonts are not required
% to define these names for all characters, and more often than not
% have /a but not /uni0061.
%
% 16#431 -> /uni0431

/ushow.uniname {
	16 10 string cvrs					% (431)
	dup length 4 le {					% (431)
		dup length 4 exch sub 7 string			% (431) 1 (-------)
		dup 0 (uni) putinterval				% (431) 1 (uni----)
		1 index 0 gt {					% (431) 1 (uni----) 1
			1 index
			3 exch 1 exch 2 add {
				1 index exch (0) putinterval
			} for
		} if						% (431) 1 (uni0---)
		dup 4 1 roll 3 1 roll				% (uni0---) (uni0---) (431) 1
		dup 0 gt { 3 add } { pop 3 } ifelse
		exch putinterval
	} {
		dup length 1 add string				% (12345) (- -----)
		dup 0 (u) putinterval				% (12345) (u -----)
		dup 2 index 1 exch putinterval
		exch pop
	} ifelse
	cvn
} def


% Show the glyph *and* do stats if necessary.
%
% code /glyph ->

/ushow.printglyph {
	systemdict /noteunicode .knownget { 2 index exch exec } if
	exch ushow.substcode 0 gt {
		glyphshow
	} {
		gsave glyphshow grestore
	} ifelse
} def

% Well $code is not in currentfont, so got to print notdef instead.
% The idea is to have resulting text width close to what it would be
% with the glyph available, at least for monospace fonts.
%
% code ->

/ushow.substitute {
	ushow.substcode { /.notdef glyphshow } repeat
} def

% Like substitute but only returns the width.

/ushow.substwidth {
	ushow.substcode /.notdef .glyphwidth pop mul
} def

/ushow.substcode { {
	16#0000 16#02FF 1 ushow.rangew	% ASCII stuff and generic Latin 
	16#0300 16#036F 0 ushow.rangew	% generic combining stuff
	16#20D0 16#20EF 0 ushow.rangew
	16#0483 16#0489 0 ushow.rangew
	16#0591 16#05A1 0 ushow.rangew
	16#1100 16#115F 2 ushow.rangew	% Hangul double-width
	16#1160 16#11F9 0 ushow.rangew	% Hangul combining
	16#FFE0 16#FFE6 2 ushow.rangew
	16#2E80 16#3098 2 ushow.rangew
	16#309D 16#4DB5 2 ushow.rangew
	16#4E00 16#9FC3 2 ushow.rangew
	16#A000 16#A4C6 2 ushow.rangew
	16#0E31 16#0E31 0 ushow.rangew	% Thai combining
	16#0E34 16#0E3A 0 ushow.rangew	% Thai combining
	16#0E47 16#0E4E 0 ushow.rangew	% Thai combining
	16#1D300 16#1D371 2 ushow.rangew
	16#1F100 16#1F1FF 2 ushow.rangew % Double-width letters
	16#1F030 16#1F061 2 ushow.rangew % Domino horizontal
	16#E0000 16#E01FF 2 ushow.rangew
	pop 1 exit
} loop } def

% code from to width -> width exit
% code from to width -> code

/ushow.rangew {
	3 index 3 index ge
	4 index 3 index le and {
		exch pop exch pop exch pop exit
	} {
		pop pop pop
	} ifelse
} def

currentdict end /unifont exch /ProcSet defineresource pop
